package cn.modoumama.common.tools;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @Description 对象操作工具
 * @Author dengqiang
 * @Date 2018/12/7 17:04
 * @Version 1.0
 **/
public class ObjectUtils {
    private static Logger logger = LoggerFactory.getLogger(ObjectUtils.class);

    /**
     * 获取对象属性的值
     * @param fieldName
     * @param object
     * @return
     */
    public static Object getValue(String fieldName, Object object) {
        String[] fieldNames = fieldName.split("\\.");
        Object value = object;
        for (int i = 0; i < fieldNames.length; i++) {
            if (value == null) {
                break;
            }
            if(StringUtils.isNotBlank(fieldNames[i])) {
                String fieldStr = fieldNames[i].trim();
                try {
                    if (value instanceof Map) {
                        value = ((Map<?, ?>) value).get(fieldStr);
                    } else {
                    	Class<?> objClass = value.getClass();
                    	while(true) {
                    		Field field = null;
                    		try {
                    			field = objClass.getDeclaredField(fieldStr);
                    		}catch(Exception e) {
                    			objClass = objClass.getSuperclass();
                        		if(objClass == null || objClass.equals(Object.class)) {
                        			throw new RuntimeException("fieldName--"+fieldName+"--无效");
                        		}
                    		}
                    		if(field != null) {
                    			field.setAccessible(true);
                    			value = field.get(value);
	                    		break;
                    		}
                    	}
                    }
                } catch (Exception e) {
                   throw new RuntimeException(e);
                }
            }else{
                throw new RuntimeException("属性--"+fieldName+"--无效");
            }
        }

        return value;
    }
    
    /**
     * 获取对象属性的值
     * @param fieldName
     * @param object
     * @return
     */
    public static void setValue(String fieldName, Object value, Object object) {
        String[] fieldNames = fieldName.split("\\.");
        for (int i = 0; i < fieldNames.length; i++) {
            if (value == null) {
                break;
            }
            if(StringUtils.isNotBlank(fieldNames[i])) {
                String fieldStr = fieldNames[i].trim();
                try {
                    if (value instanceof Map) {
                        value = ((Map<?,?>) value).get(fieldStr);
                    } else {
                    	Class<?> objClass = object.getClass();
                    	while(true) {
                    		Field field = null;
                    		try {
                    			field = objClass.getDeclaredField(fieldStr);
                    		}catch(Exception e) {
                    			objClass = objClass.getSuperclass();
                        		if(objClass == null || objClass.equals(Object.class)) {
                        			throw new RuntimeException("fieldName--"+fieldName+"--无效");
                        		}
                    		}
                    		if(field != null) {
                    		    if(i < fieldNames.length-1){
                                    field.setAccessible(true);
                                    Object obj = field.get(object);
                                    if(obj == null){
                                        Class clazz = field.getType();
                                        obj = clazz.newInstance();
                                        field.set(object, obj);
                                    }
                                    object = obj;
                                    break;
                                }else {
                                    try {
                                        field.setAccessible(true);
                                        field.set(object, value);
                                        break;
                                    } catch (Exception e) {
                                        throw new RuntimeException(fieldName + "--数据类型不匹配");
                                    }
                                }
                    		}
                    	}
                    }
                } catch (Exception e) {
                   throw new RuntimeException(e);
                }
            }else{
            	throw new RuntimeException("属性--"+fieldName+"--无效");
            }
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> T parsValue(Class<T> clazz, String value) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
        if (StringUtils.isNotBlank(value)) {
            value = value.trim();
            if (clazz == String.class) {
                return (T) value;
            } else if (!"".equals(value)) {
                //基本类型
                if (clazz.isPrimitive()) {
                    return (T) parsTypeValue(clazz, value);
                }
                Method valueOf = null;
                try {
                	valueOf = clazz.getMethod("valueOf", String.class);
                	return (T) valueOf.invoke(null, value);
                }catch(Exception e) {
                	try {
                		valueOf = clazz.getMethod("valueOf", double.class);
                		Double val = Double.valueOf(value);
                		return (T) valueOf.invoke(null, val);
                	 }catch(Exception e1) {
                		 
                	 }
                }
            }
        }
        return null;
    }

    /**
     * 把字符串解析成基本类型
     *
     * @param clazz 需要转换成的类型
     * @param value 字符串
     * @return 返回传入的值
     */
    public static <T> Object parsTypeValue(Class<T> clazz, String value) {
        if (clazz == Byte.TYPE) {
            return Byte.parseByte(value);
        } else if (clazz == Short.TYPE) {
            return Short.parseShort(value);
        } else if (clazz == Integer.TYPE) {
            return Integer.parseInt(value);
        } else if (clazz == Long.TYPE) {
            return Long.parseLong(value);
        } else if (clazz == Boolean.TYPE) {
            return Boolean.parseBoolean(value);
        } else if (clazz == Character.TYPE) {
            return value.charAt(0);
        } else if (clazz == Float.TYPE) {
            return Float.parseFloat(value);
        } else if (clazz == Double.TYPE) {
            return Double.parseDouble(value);
        }
        return null;
    }

    public static Class<?> getPropertyType(Class<?> clazz, String fieldName) {
        String[] fieldNames = fieldName.split("\\.");
        for (int i = 0; i < fieldNames.length; i++) {
            if(StringUtils.isNotBlank(fieldNames[i])) {
                String fieldStr = fieldNames[i].trim();
                try {
                    if(Map.class.isAssignableFrom(clazz)){
                        clazz = Object.class;
                        break;
                    }else{
                    	Class<?> objClass = clazz;
                    	while(true) {
                    		Field field = null;
                    		try {
                    			field = objClass.getDeclaredField(fieldStr);
                    		}catch(Exception e) {
                    			objClass = objClass.getSuperclass();
                        		if(objClass == null || objClass.equals(Object.class)) {
                        			throw new RuntimeException("fieldName无效");
                        		}
                    		}
                    		if(field != null) {
	                    		clazz = field.getType();
	                    		break;
                    		}
                    	}
                    }

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }else{
                throw new RuntimeException("fieldName无效");
            }
        }
        return clazz;
    }

    public static <T>T convert(Map<String, Object> map, Class<T> t) throws Exception {
        T object = t.newInstance();
        BeanWrapper bean = new BeanWrapperImpl(object);
        bean.setAutoGrowNestedPaths(true);
        for (Map.Entry<String, Object> entry :map.entrySet()) {
            try {
                bean.setPropertyValue(entry.getKey(), entry.getValue());
            } catch (BeansException e) {
                logger.info( e.getMessage());
            }
        }
        return object;
    }

    /**
     * 获取对象第一个对应方法名称的方法
     * @param object
     * @param methodName
     * @return
     */
    public static Method getMethod(Object object, String methodName){
        Method method = null;
        if(object != null){
            method = getMethod(object.getClass(), methodName);
        }
        return method;
    }

    /**
     * 获取类第一个对应方法名称的方法
     * @param clazz
     * @param methodName
     * @return
     */
    public static Method getMethod(Class clazz, String methodName){
        Method method = null;
        if(clazz != null && StringUtils.isNotBlank(methodName)){
            Method[] methods = clazz.getMethods();
            for (int i = 0; i < methods.length; i++) {
                if(methods[i].getName().equals(methodName)){
                    method = methods[i];
                    break;
                }
            }
        }

        return method;
    }

    /**
     * 获取方法的参数
     * @param method
     * @return
     * @throws Exception
     */
    public static MethodParameter[] getMethodParameter(Method method) throws Exception {
        MethodParameter[] parameters = null;
        if(method != null) {
            ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
            Class<?>[] pType = method.getParameterTypes();
            if(pType != null && pType.length>0) {
                parameters = new MethodParameter[pType.length];
                for (int i = 0; i < pType.length; i++) {
                    MethodParameter methodParameter = new MethodParameter(method, i);
                    methodParameter.initParameterNameDiscovery(parameterNameDiscoverer);
                    parameters[i] = methodParameter;
                }
            }
        }
        return parameters;
    }

    /**
     * 获取 目标对象
     * @param proxy 代理对象
     * @return
     * @throws Exception
     */
    public static Object getTarget(Object proxy) throws Exception {

        if(!AopUtils.isAopProxy(proxy)) {
            return proxy;//不是代理对象
        }

        if(AopUtils.isJdkDynamicProxy(proxy)) {
            return getJdkDynamicProxyTargetObject(proxy);
        } else { //cglib
            return getCglibProxyTargetObject(proxy);
        }

    }

    /**
     * 获取Cglib代理的对象
     * @param proxy
     * @return
     * @throws Exception
     */
    private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
        Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
        h.setAccessible(true);
        Object dynamicAdvisedInterceptor = h.get(proxy);

        Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
        advised.setAccessible(true);

        Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();

        return target;
    }

    /**
     * 获取JdkDynamic代理的对象
     * @param proxy
     * @return
     * @throws Exception
     */
    private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
        Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
        h.setAccessible(true);
        AopProxy aopProxy = (AopProxy) h.get(proxy);

        Field advised = aopProxy.getClass().getDeclaredField("advised");
        advised.setAccessible(true);

        Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();

        return target;
    }
}
